home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / program / ixemlsrc.lha / ixemul / library / lseek.c < prev    next >
C/C++ Source or Header  |  1995-12-23  |  7KB  |  267 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *
  5.  *  This library is free software; you can redistribute it and/or
  6.  *  modify it under the terms of the GNU Library General Public
  7.  *  License as published by the Free Software Foundation; either
  8.  *  version 2 of the License, or (at your option) any later version.
  9.  *
  10.  *  This library is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  *  Library General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU Library General Public
  16.  *  License along with this library; if not, write to the Free
  17.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  lseek.c,v 1.1.1.1 1994/04/04 04:30:29 amiga Exp
  20.  *
  21.  *  lseek.c,v
  22.  * Revision 1.1.1.1  1994/04/04  04:30:29  amiga
  23.  * Initial CVS check in.
  24.  *
  25.  *  Revision 1.1  1992/05/14  19:55:40  mwild
  26.  *  Initial revision
  27.  *
  28.  */
  29.  
  30. #define KERNEL
  31. #include "ixemul.h"
  32. #include "kprintf.h"
  33.  
  34. #include <string.h>
  35.  
  36. static inline int
  37. __extend_file (struct file *f, int add_to_eof, int *err)
  38. {
  39.   int res = 0;
  40.   int buf_size, written;
  41.   char *buf;
  42.  
  43.   /* now you know perhaps, that starting with OS2.0 there's a packet that
  44.      sets the size of a file (used in [f]truncate()). Too bad, that the 
  45.      following statement from the autodocs render this packet useless... :
  46.  
  47.      `` Do NOT count on any specific values to be in the extended area. ''
  48.    
  49.      Since **IX requires the new area to be zero'd, we can just as well
  50.      write zeros without the use of the new packet ;-(( */
  51.   
  52.       
  53.   buf_size = add_to_eof > 32*1024 ? 32*1024 : add_to_eof;
  54.   while (! (buf = (char *) kmalloc (buf_size)) && buf_size)
  55.     buf_size >>= 1;
  56.   if (buf)
  57.     {
  58.       bzero (buf, buf_size);
  59.  
  60.       for (written = 0; written < add_to_eof; )
  61.         {
  62.       SendPacket3(f,__rwport,ACTION_WRITE,f->f_fh->fh_Arg1,(long)buf,buf_size);
  63.       __wait_packet(&f->f_sp);
  64.       res = LastResult (f);
  65.           if (res < 0)
  66.             {
  67.               *err = LastError (f);
  68.               break;
  69.             }
  70.           written += res;
  71.           buf_size = add_to_eof - written > buf_size ? 
  72.                buf_size : add_to_eof - written;
  73.     }
  74.       kfree (buf);
  75.     }
  76.   else
  77.     {
  78.       *err = ENOMEM;
  79.       res = -1;
  80.     }
  81.  
  82.   if (res >= 0)
  83.     {
  84.       SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  85.      __wait_packet (&f->f_sp);
  86.       LastError(f) = 0;
  87.       SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  88.      __wait_packet (&f->f_sp);
  89.      res = LastError (f) ? -1 : LastResult (f);
  90.      *err = __ioerr_to_errno (LastError (f));
  91.    }
  92.  
  93.   return res;
  94. }
  95.  
  96.  
  97. off_t
  98. lseek (int fd, off_t off, int dir)
  99. {
  100.   struct file *f = u.u_ofile[fd];
  101.   int omask;
  102.   int err, res;
  103.   int previous_pos = 0, shouldbe_pos;
  104.  
  105.   /* if this is an open fd */
  106.   if (fd >= 0 && fd < NOFILE && f)
  107.     {
  108.       if (f->f_type == DTYPE_FILE)
  109.     {
  110.           if (HANDLER_NIL(f))
  111.         {
  112.           errno = ESPIPE;
  113.           KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  114.           return -1;
  115.         }
  116.  
  117.       omask = syscall (SYS_sigsetmask, ~0);
  118.       __get_file (f);
  119.       __wait_packet(&f->f_sp);
  120.  
  121.       /* there's a subtle difference between Unix lseek() and AmigaDOS
  122.        * Seek(): lseek() returns the *current* position of the `pointer',
  123.        * Seek() returns the *previous* position. So in some cases, we
  124.        * have to do another Seek() to find out where we are.
  125.        * Thanks Mike for pointing me at this! */
  126.  
  127.       switch (dir)
  128.         {
  129.         case SEEK_SET:
  130.           /* previous doesn't matter, don't need to seek */
  131.           previous_pos = 0;
  132.           break;
  133.  
  134.         case SEEK_CUR:
  135.           /* first find out current position */
  136.           LastError(f) = 0;
  137.           SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_CURRENT);
  138.           __wait_packet (&f->f_sp);
  139.           if (LastError(f) || LastResult(f) < 0)
  140.             {
  141.               err = __ioerr_to_errno(LastError(f));
  142.               previous_pos = -1;
  143.             }
  144.           else
  145.             previous_pos = LastResult(f);
  146.           break;
  147.           
  148.         case SEEK_END:
  149.           /* first find out end position (have to do twice.. argl) */
  150.           SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  151.           __wait_packet (&f->f_sp);
  152.           LastError(f) = 0;
  153.           SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_CURRENT);
  154.           __wait_packet (&f->f_sp);
  155.           if (LastError(f) || LastResult(f) < 0)
  156.             {
  157.               err = __ioerr_to_errno(LastError(f));
  158.               previous_pos = -1;
  159.             }
  160.           else
  161.             previous_pos = LastResult(f);
  162.           break;
  163.         }
  164.       
  165.       shouldbe_pos = previous_pos + off;
  166.       if (shouldbe_pos < 0)
  167.         {
  168.           /* that way we make sure that invalid seek errors later result
  169.              from seeking past eof, so we can enlarge the file */
  170.  
  171.           err = EINVAL;
  172.           res = -1;
  173.         }
  174.       else if (previous_pos >= 0)
  175.         {
  176.           /* reset the error field */
  177.           LastError(f) = 0;
  178.           SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,off,dir-1);
  179.           __wait_packet(&f->f_sp);
  180.  
  181.           if (LastError (f) == ERROR_SEEK_ERROR)
  182.             {
  183.               /* in this case, assume the user wanted to seek past eof.
  184.                  Thus get the current eof position, so that we can
  185.                  tell __extend_file how much to enlarge the file */
  186.           
  187.           LastError(f) = 0;
  188.           SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_END);
  189.           __wait_packet (&f->f_sp);
  190.             }
  191.       
  192.           if (LastError (f) || LastResult (f) < 0)
  193.             {
  194.               err = __ioerr_to_errno(LastError(f));
  195.               res = -1;
  196.             }
  197.           else
  198.             {
  199.               err = 0;
  200.  
  201.               if (previous_pos != shouldbe_pos)
  202.             {
  203.               SendPacket3(f,__rwport,ACTION_SEEK,f->f_fh->fh_Arg1,0,OFFSET_CURRENT);
  204.               __wait_packet (&f->f_sp);
  205.               if (LastError (f) || LastResult(f) < 0)
  206.                 {
  207.                       err = __ioerr_to_errno(LastError(f));
  208.                       res = -1;
  209.                     }
  210.               else
  211.                     res = LastResult(f);
  212.  
  213.                   if (res >= 0 && res < shouldbe_pos && (f->f_flags & FWRITE))
  214.                     {
  215.                       /* extend the file... */
  216.                   res = __extend_file (f, shouldbe_pos - res, &err);
  217.                 }
  218.             }
  219.           else
  220.             res = shouldbe_pos;
  221.             }
  222.         }
  223.       else
  224.         res = -1;
  225.       
  226.       LastResult(f) = 0;
  227.       __release_file (f);
  228.       syscall (SYS_sigsetmask, omask);
  229.       errno = err;
  230.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  231.       return res;
  232.     }
  233.       else if (f->f_type == DTYPE_MEM)
  234.     {
  235.       int real_off;
  236.       int old_off;
  237.  
  238.       omask = syscall (SYS_sigsetmask, ~0);
  239.       __get_file (f);
  240.       old_off = f->f_mf.mf_offset;
  241.       
  242.       real_off = (dir == L_SET ? off : 
  243.               (dir == L_INCR ? 
  244.                old_off + off : f->f_stb.st_size + off));
  245.       if (real_off < 0) real_off = 0;
  246.       else if (real_off > f->f_stb.st_size) real_off = f->f_stb.st_size;
  247.       f->f_mf.mf_offset = real_off;
  248.       __release_file (f);
  249.       syscall (SYS_sigsetmask, omask);
  250.       return old_off;
  251.     }
  252.       else
  253.     {
  254.       errno = ESPIPE;
  255.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  256.     }
  257.     }
  258.   else
  259.     {
  260.       errno = EBADF;
  261.       KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  262.     }
  263.  
  264.   return -1;
  265. }
  266.  
  267.